/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.univcasa.managing.impl;

import com.univcasa.db.model.CompteEtudiant;
import com.univcasa.db.model.ComptePersonnel;
import com.univcasa.managing.LdapDBManager;
import com.univcasa.managing.StudentLoginManager;
import com.univcasa.managing.util.LDAPHandler;
import com.univcasa.managing.util.LdapConfigurator;
import com.univcasa.managing.util.User;
import com.univcasa.managing.util.exception.LDAPException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchResult;
import org.apache.log4j.Logger;

/**
 *
 * @author issam
 */
public class LdapDBManagerImpl implements LdapDBManager {

    private LDAPHandler handler;
    private StudentLoginManager loginManager;

    public LdapDBManagerImpl() {

        handler = new LDAPHandler();
        LdapConfigurator.configureHandler(handler);
        try {
            handler.authenticate();
        } catch (LDAPException ex) {
            ex.printStackTrace();
        }
        loginManager = new LoginManagerImpl(this);
    }

    private static Logger log = Logger.getLogger(LdapDBManagerImpl.class);

    public List ajoutComptesLdap(List comptes){

        List results = new ArrayList();
        for (Iterator itr = comptes.iterator(); itr.hasNext();){
            CompteEtudiant compte = (CompteEtudiant) itr.next();
            boolean ajout = ajoutCompteEtudiantLdap(compte);
            if (ajout == false){
                results.add(compte);
            }
        }
        return results;
    }

        /**@Todo
     * delete the local test filter uid=etud from production
     * @return
     */

    public List recupererListeStudentsLdap() {

        NamingEnumeration results;
        String[] attributs = new String[]{"uid","sn","givenName","supannOrganisme","supannEtuId","supannCodeINE","supannEtuDiplome","supannEtuEtape","supannCivilite","postalAddress"};
        handler.setAttributes( attributs );
        handler.setFilter("(&(eduPersonPrimaryAffiliation=student)(!(uid=etud*)))");
        try {
            results = handler.search();
            return enumOfAttribToComptesStudents(results);
        } catch (LDAPException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    public CompteEtudiant recupererEtudiantByApogee(String apogee) {

        NamingEnumeration results;
        String[] attributs = new String[]{"uid","sn","givenName","supannOrganisme","supannEtuId","supannCodeINE","supannEtuDiplome","supannEtuEtape","supannCivilite","postalAddress"};
        handler.setAttributes( attributs );
        handler.setFilter("(&(eduPersonPrimaryAffiliation=student)(supannEtuId="+apogee+")))");
        try {
            results = handler.search();
            log.info("INFO get Std from LDAP apogee " +apogee);
            return listOfOne2CompteStd( enumOfAttribToComptesStudents(results) );
        } catch (LDAPException ex) {
            log.error("ERROR get Std from LDAP apogee " +apogee ,ex);
            return null;
        }
    }

    public List recupererEtudiantErrored() {

        NamingEnumeration results;
        String[] attributs = new String[]{"uid","sn","givenName","supannOrganisme","supannEtuId","supannCodeINE","supannEtuDiplome","supannEtuEtape","supannCivilite","postalAddress"};
        handler.setAttributes( attributs );
        handler.setFilter("(&(eduPersonPrimaryAffiliation=student)(!(eduPersonAffiliation=member))))");
        try {
            results = handler.search();
            log.info("INFO get Std from LDAP apogee ");
            return enumOfAttribToComptesStudents( results );
        } catch (LDAPException ex) {
            log.error("ERROR get Std from LDAP apogee " ,ex);
            return null;
        }
    }


    public boolean majCompteEtudiantLdap(CompteEtudiant etudiant) {
        User user = new User( etudiant.getUid(),
                                etudiant.getPrenom(),
                                etudiant.getNom(),                                
                                etudiant.getMailPerso(),
                                etudiant.getEtab()) ;
        user.completerCompteEtudiant( etudiant.getApogee(),
                                        etudiant.getPassword(),
                                        etudiant.getCne(),
                                        etudiant.getDiplome(),
                                        etudiant.getEtape(),
                                        etudiant.getAdresse(),
                                        etudiant.getSexe() ) ;
        //ajout de l'entrée sur ldap
        try {
            handler.updateEntry( user );
            log.info("SUCCESS Update Compte a LDAP" + etudiant.getApogee() + " " + etudiant.getUid() );
            return true;
        } catch (LDAPException ex) {
            log.error("FAILURE Update Compte a LDAP" + etudiant.getApogee() + " " + etudiant.getUid() ,ex);
            return false;
        }
    }


    public boolean ajoutComptePersLdap(ComptePersonnel pers) {
        loginManager.getPersAvailablelogin(pers);

        User user = new User( pers.getUid(),
                                pers.getPrenom(),
                                pers.getNom(),
                                pers.getMailPerso(),
                                pers.getEtab()) ;
        user.completerComptePersonnel( pers.getSom(),
                                        pers.getPassword(),
                                        pers.getSexe() ) ;

        //ajout de l'entrée sur ldap
        try {
            handler.addEntry( user);
            log.info("SUCCESS Add Compte Pers a LDAP" + pers.getSom() + " " + pers.getUid() );
            return true;
        } catch (LDAPException ex) {        
            log.error("FAILURE Add Compte a LDAP" + pers.getSom() + " " + pers.getUid() ,ex);
            return false;
        }
    }

    public boolean majComptePersLdap(ComptePersonnel pers) {

        User user = new User( pers.getUid(),
                                pers.getPrenom(),
                                pers.getNom(),
                                pers.getMailPerso(),
                                pers.getEtab()) ;
        user.completerComptePersonnel( pers.getSom(),
                                        pers.getPassword(),
                                        pers.getSexe() ) ;
        //ajout de l'entrée sur ldap
        try {
            handler.updateEntry( user );
            log.info("SUCCESS Add Compte Pers a LDAP" + pers.getSom() + " " + pers.getUid() );
            return true;
        } catch (LDAPException ex) {
            log.error("FAILURE Add Compte a LDAP" + pers.getSom() + " " + pers.getUid() ,ex);
            return false;
        }
    }

    public ComptePersonnel recupererPersBySom(String som) {
        NamingEnumeration results;
        String[] attributs = new String[]{"uid","sn","givenName","supannOrganisme","supannEmpId","supannCivilite","eduPersonPrimaryAffiliation","userPassword"};
        handler.setAttributes( attributs );
        handler.setFilter("(&(|(eduPersonPrimaryAffiliation=employee)(eduPersonPrimaryAffiliation=faculty))(supannEmpId="+som+"))");
        try {
            results = handler.search();
            log.info("INFO get Pers from LDAP som " + som);
            return listOfOne2ComptePers( enumOfAttribToComptesPers(results) );
        } catch (LDAPException ex) {
            log.error("ERROR get Pers from LDAP som " +som ,ex);
            return null;
        }
    }

    public List ajoutComptesPersLdap(List comptes) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public List recupererListesomPers() {
        NamingEnumeration results;
        String[] attributs = new String[]{"supannEmpId"};
        handler.setAttributes( attributs );
        handler.setFilter("(&(|(eduPersonPrimaryAffiliation=faculty)(eduPersonPrimaryAffiliation=employee))(!(supannEmpId=1000)))");
        try {
            results = handler.search();
            return enumOfAttribToList( results );
        } catch (LDAPException ex) {
            log.error("ERROR getting list of pers som's", ex);
            return null;
        }
    }

    public List recupererListePersLdap() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public List searchStdsByCriteres(HashMap criteres) {

        String cne = (String) criteres.get("cne");
        String apogee = (String) criteres.get("apogee");
        String nom = (String) criteres.get("nom");
        String prenom = (String) criteres.get("prenom");
        String cin = (String) criteres.get("cin");

        cne = (cne==null ||"".equals(cne) )?"*":cne;
        apogee = (apogee==null || "".equals(apogee))?"*":apogee;
        nom = (nom==null ||"".equals(nom) )?"*":nom;
        prenom = (prenom==null ||"".equals(prenom) )?"*":prenom;
        cin = (cin==null ||"".equals(cin) )?"*":cin;

        if (cne.equals("*") && apogee.equals("*") && nom.equals("*")&& prenom.equals("*")  ){
            cne=cin;
        }

        NamingEnumeration results;
        String[] attributs = new String[]{"uid","sn","givenName","supannOrganisme","supannEtuId","supannCodeINE","supannEtuDiplome","supannEtuEtape","supannCivilite","postalAddress","userPassword"};
        handler.setAttributes( attributs );
        handler.setFilter("(&(givenName="+prenom+")(sn="+nom+")(supannCodeINE="+cne+")(supannEtuId="+apogee+")(eduPersonPrimaryAffiliation=student))");
        try {
            results = handler.search();
            log.info("INFO get Std from LDAP apogee ");
            return enumOfAttribToComptesStudents( results );
        } catch (LDAPException ex) {
            log.error("ERROR get Std from LDAP apogee " ,ex);
            return null;
        }
    }

    public boolean ajoutCompteEtudiantLdap(CompteEtudiant etudiant) {

        //generer et verifier l'availability du login:
        loginManager.getAvailablelogin(etudiant);

        User user = new User( etudiant.getUid(),
                                etudiant.getPrenom(),
                                etudiant.getNom(),
                                etudiant.getMailPerso(),
                                etudiant.getEtab()) ;
        user.completerCompteEtudiant( etudiant.getApogee(),
                                        etudiant.getPassword(),
                                        etudiant.getCne(),
                                        etudiant.getDiplome(),
                                        etudiant.getEtape(),
                                        etudiant.getAdresse(),
                                        etudiant.getSexe() ) ;

        //ajout de l'entrée sur ldap
        try {
            handler.addEntry( user);
            log.info("SUCCESS Add Compte a LDAP" + etudiant.getApogee() + " " + etudiant.getUid() );
            return true;
        } catch (LDAPException ex) {
            log.error("FAILURE Add Compte a LDAP" + etudiant.getApogee() + " " + etudiant.getUid() ,ex);
            return false;
        }        
    }

    public List recupererListeUids(String nom, String prenom){

        return null;
    }

    public List recupererListeUids(String uidPattern) {

        NamingEnumeration results;
        String[] attributs = new String[]{"uid"};
        handler.setAttributes( attributs );
        handler.setFilter("(uid="+uidPattern+")");
        try {
            results = handler.search();
            return enumOfAttribToList( results );
        } catch (LDAPException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    public List recupererListeApogeeEtudiants() {

        NamingEnumeration results;
        String[] attributs = new String[]{"supannEtuId"};
        handler.setAttributes( attributs );
        handler.setFilter("eduPersonPrimaryAffiliation=student");
        try {
            results = handler.search();
            return enumOfAttribToList( results );
        } catch (LDAPException ex) {
            log.error("ERROR getting list of students apogee's", ex);
            return null;
        }
    }

    private CompteEtudiant listOfOne2CompteStd(List lista){

        CompteEtudiant etudiant = new CompteEtudiant();
        for (Iterator itr = lista.iterator() ; itr.hasNext();){
            etudiant = (CompteEtudiant) itr.next();
            break;
        }
        return etudiant;
    }
    private ComptePersonnel listOfOne2ComptePers(List lista){

        ComptePersonnel pers = new ComptePersonnel();
        for (Iterator itr = lista.iterator() ; itr.hasNext();){
            pers = (ComptePersonnel) itr.next();
            break;
        }
        return pers;
    }

    private List enumOfAttribToComptesPers(NamingEnumeration nenum){
        List answer = new ArrayList();
        try {
            while (nenum != null && nenum.hasMore()) {
				//Lecture d'une entrée
				SearchResult entry = (SearchResult) nenum.next();
                                //les attributs de l'entrée
				Attributes attrs = entry.getAttributes();
				if (attrs == null) {
					// aucun attributs associés à ce DN...
					log.warn("aucun attributs associés à ce DN");
				} else {
					//Parcours de tous les attributs
                                    ComptePersonnel pers = new ComptePersonnel();
					for (NamingEnumeration attEnum = attrs.getAll();
					attEnum.hasMoreElements();)
                                        {
                                            Attribute attr = (Attribute) attEnum.next();
                                            String attrId = attr.getID();
                                            for(Enumeration vals = attr.getAll(); vals.hasMoreElements();){
                                                if (! attrId.equals( "userPassword" )){
                                                String val = (String) vals.nextElement();
                                                pers.setLdapAttrib(attrId, val);
                                                }
                                                else{
                                                    String val = new String( (byte[]) vals.nextElement());
                                                    pers.setLdapAttrib(attrId, val);
                                                }
                                            }
                                        }
                                    answer.add(pers);
                                }
                        }
                    } catch (NamingException nex) {
            log.error("error", nex);
        }
        return answer ;

    }

    private List enumOfAttribToComptesStudents(NamingEnumeration nenum){
        List answer = new ArrayList();
        try {
            while (nenum != null && nenum.hasMore()) {
				//Lecture d'une entrée
				SearchResult entry = (SearchResult) nenum.next();
                                //les attributs de l'entrée
				Attributes attrs = entry.getAttributes();
				if (attrs == null) {
					// aucun attributs associés à ce DN...
					log.warn("aucun attributs associés à ce DN");
				} else {
					//Parcours de tous les attributs
                                    CompteEtudiant etud = new CompteEtudiant();
					for (NamingEnumeration attEnum = attrs.getAll();
					attEnum.hasMoreElements();)
                                        {
                                            Attribute attr = (Attribute) attEnum.next();
                                            String attrId = attr.getID();
                                            for(Enumeration vals = attr.getAll(); vals.hasMoreElements();){
                                                if (! attrId.equals( "userPassword" )){
                                                String val = (String) vals.nextElement();
                                                etud.setLdapAttrib(attrId, val);
                                                }
                                                else{
                                                    String val = new String( (byte[]) vals.nextElement());
                                                    etud.setLdapAttrib(attrId, val);
                                                }
                                            }
                                        }
                                    answer.add(etud);
                                }
                        }
                    } catch (NamingException nex) {
            log.error("error", nex);
        }
        return answer ;

    }

    private List enumOfAttribToList(NamingEnumeration nenum){
        List answer = new ArrayList();
        try {
            while (nenum != null && nenum.hasMore()) {
				//Lecture d'une entrée
				SearchResult entry = (SearchResult) nenum.next();
                                //les attributs de l'entrée
				Attributes attrs = entry.getAttributes();
				if (attrs == null) {
					// aucun attributs associés à ce DN...
					log.warn("aucun attributs associés à ce DN");
				} else {
					//Parcours de tous les attributs
					for (NamingEnumeration attEnum = attrs.getAll();
					attEnum.hasMoreElements();)
                                        {
                                            Attribute attr = (Attribute) attEnum.next();
                                            String attrId = attr.getID();
                                            for(Enumeration vals = attr.getAll(); vals.hasMoreElements();){
                                                String val = (String) vals.nextElement();
                                                answer.add(val);
                                            }
                                        }
                                }
                        }
                    } catch (NamingException nex) {
            log.error("error", nex);
        }
        return answer ;
    }


}
